home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / netz / amyboard / amiga / args.c < prev    next >
C/C++ Source or Header  |  1995-08-12  |  20KB  |  804 lines

  1. /***
  2. ***  args.c -- argument parsing system for AmyBoard
  3. ***
  4. *** ------------------------------------------------------------------------
  5. ***  This program is free software; you can redistribute it and/or modify
  6. ***  it under the terms of the GNU General Public License as published by
  7. ***  the Free Software Foundation; either version 2 of the License, or
  8. ***  (at your option) any later version.
  9. ***
  10. ***  This program is distributed in the hope that it will be useful,
  11. ***  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ***  GNU General Public License for more details.
  14. ***
  15. ***  You should have received a copy of the GNU General Public License
  16. ***  along with this program; if not, write to the Free Software
  17. ***  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. *** ------------------------------------------------------------------------
  19. **/
  20. /**/
  21.  
  22.  
  23. /***** ParseArgs() *********************************************************
  24. *
  25. *   NAME
  26. *       ParseArgsA() - universal, tag based ReadArgs() replacement
  27. *
  28. *   SYNOPSIS
  29. *       ULONG Sucess = ParseArgsA(int argc, char *argv[],
  30. *                                 struct TagItem *taglist);
  31. *
  32. *       ULONG Success = ParseArgs(int argc, char *argv[],
  33. *                                 Tag FirstTag, ...);
  34. *
  35. *   FUNCTION
  36. *       ParseArgsA() and its stack based version ParseArgs() try to
  37. *       replace dos.library/ReadArgs(). Unlike ReadArgs() they can
  38. *       scan CLI arguments, icon tooltypes and preferences files
  39. *       with one function call. Arguments are described with tags,
  40. *       thus much more flexible.
  41. *
  42. *       Memory allocations are done with malloc(), you need not
  43. *       free any memory. (If you don't like malloc(), use a
  44. *       Exec-Pool based replacement like dev/misc/mempools.lha
  45. *       from Aminet.)
  46. *
  47. *       These tags are known by ParseArgs():
  48. *
  49. *           PARSEARGS_ARGNAME - argument name (STRPTR); unlike
  50. *               usual tag arrays the order os the tag items is
  51. *               meaningful: Any arguments description must start
  52. *               with a PARSEARGS_ARGNAME tag and certain other
  53. *               tags (PARSEARGS_TYPE, PARSEARGS_VALPTR,
  54. *               PARSEARGS_MULTIARG, PARSEARGS_REQUIRED) always
  55. *               refer to the last PARSEARGS_ARGNAME. The order
  56. *               of the arguments, however is meaningless.
  57. *
  58. *           PARSEARGS_TYPE - argument type (ULONG), one of
  59. *
  60. *               PARSEARGS_TYPE_STRING   string (default)
  61. *
  62. *               PARSEARGS_TYPE_BOOL     boolean value, like
  63. *                   "true", "Yes", "on" (which return TRUE) or
  64. *                   "false", "no" or "off" (which return FALSE)
  65. *
  66. *                   This argument type is handled like a mixture
  67. *                   of the /T and /S switches of ReadArgs():
  68. *                   Just using this argument (like QUIET/S)
  69. *                   toggles the value, but you may explicitly
  70. *                   select a value with "QUIET=true". However,
  71. *                   QUIET "true" won't work, as the program
  72. *                   just doesn't notice, that the following
  73. *                   argument refers to the QUIET switch.
  74. *
  75. *               PARSEARGS_TYPE_INTEGER  integer value
  76. *
  77. *               PARSEARGS_TYPE_FLOAT    float value
  78. *
  79. *       PARSEARGS_VALPTR - pointer (APTR *) where to store the
  80. *           argument value; you might setup default values by
  81. *           just storing them where this pointer points to.
  82. *           If this tag is missing, the respective arguments
  83. *           are just ignored.
  84. *
  85. *       PARSEARGS_REQUIRED - (BOOL) treat it as an error, if
  86. *           this argument wasn't present. (IoErr() will be set
  87. *           to ERROR_REQUIRED_ARG_MISSING in that case.) Note,
  88. *           that it does not make any difference, if the argument
  89. *           was given on the command line or in a prefs file, for
  90. *           example.
  91. *
  92. *       PARSEARGS_MULTIARG - (BOOL) argument may occur more than
  93. *           once, a NULL terminated array of values is returned.
  94. *           (Usually old values are just overwritten.) Note, that
  95. *           it is possible, that a NULL is returned instead of an
  96. *           array, indicating, that the argument wasn't mentioned
  97. *           at all. (You can suppress this by using both
  98. *           PARSEARGS_MULTIARG and PARSEARGS_REQUIRED.)
  99. *
  100. *           It is not possible to use this tag with boolean
  101. *           arguments. (This wouldn't make much sense, IMO.)
  102. *
  103. *       PARSEARGS_PREFSFILE - name of a prefsfile (STRPTR),
  104. *           ParseArgs() will look if the file exists. If it does,
  105. *           it will be opened and its lines will be interpreted as
  106. *           if they were icon tooltypes. You may supply more than
  107. *           one prefs filename, but no more than one will be
  108. *           opened. (Thus the program may look, for example, in
  109. *           S: and ENV: for prefsfiles.)
  110. *
  111. *       PARSEARGS_HELPSTRING - help string (STRPTR) to put out,
  112. *           when the user asks for a CLI template by giving a
  113. *           "?" as the first CLI argument. By default ParseArgs()
  114. *           generates a template like that of ReadArgs().
  115. *
  116. *
  117. *   INPUTS
  118. *       argc, argv - the usual main() arguments; argc = 0 is
  119. *           expected, if, and only if, the program is run from
  120. *           workbench; in that case argv must hold the WBStartup
  121. *           message (this is the usual convention as for SAS/C).
  122. *
  123. *
  124. *   EXAMPLE
  125. *       \**
  126. *       ***  Example similar to
  127. *       ***     FROM=FROMFILE/A/M/K,TO/A/K,QUIET/S,ALL/S
  128. *       **\
  129. *       int main(int argc, char *argv[])
  130. *
  131. *       { STRPTR *from;
  132. *         STRPTR to;
  133. *         ULONG quiet = FALSE, all = FALSE;
  134. *
  135. *         if (!ParseArgs(argc, argv,
  136. *                   PARSEARGS_ARGNAME, "from=fromfile",
  137. *                   PARSEARGS_VALPTR, &from,
  138. *                   PARSEARGS_MULTIARG, TRUE,
  139. *                   PARSEARGS_REQUIRED, TRUE,
  140. *
  141. *                   PARSEARGS_ARGNAME, "to",
  142. *                   PARSEARGS_VALPTR, &to,
  143. *                   PARSEARGS_REQUIRED, TRUE,
  144. *
  145. *                   PARSEARGS_ARGNAME, "quiet",
  146. *                   PARSEARGS_VALPTR, &quiet,
  147. *                   PARSEARGS_TYPE, PARSEARGS_TYPE_BOOL,
  148. *
  149. *                   PARSEARGS_ARGNAME, "all",
  150. *                   PARSEARGS_VALPTR, &all,
  151. *                   PARSEARGS_TYPE, PARSEARGS_TYPE_BOOL,
  152. *
  153. *                   PARSEARGS_PREFSFILE, "ENV:MyPrefs",
  154. *                   PARSEARGS_PREFSFILE, "S:MyPrefs",
  155. *                   TAG_DONE))
  156. *         { printf("Error %ld happened.\n", IoErr());
  157. *           exit(10);
  158. *         }
  159. *
  160. *         \**
  161. *         ***  Not checking from == NULL, as this argument
  162. *         ***  was required.
  163. *         **\
  164. *         while (*from)
  165. *         { printf("from argument: %s\n", *from++);
  166. *         }
  167. *         printf("to argument: %s\n", to);
  168. *         printf("quiet status: %ld, all status %ld.\n");
  169. *       }
  170. *
  171. *       \**
  172. *       ***  Dice's entry point when starting from Workbench.
  173. *       **\
  174. *       #if defined(_DCC)
  175. *       int wbmain(struct WBStartup *wbs)
  176. *       { return(main(0, (char **) argv)); }
  177. *       #endif
  178. *
  179. *
  180. *   BUGS
  181. *       Currently it is not possible to use arguments without
  182. *       argument name. (Like FROM instead of FROM/K.) Just because
  183. *       I was too lazy. Neither are project names used. Both left
  184. *       to the future.
  185. *
  186. *
  187. *   RESULT
  188. *       TRUE for success, FALSE otherwise; you might examine
  189. *       IoErr() in the latter case.
  190. *
  191. *   SEE ALSO
  192. *       dos.library/ReadArgs()
  193. *
  194. ***************************************************************************/
  195. /**/
  196.  
  197.  
  198.  
  199.  
  200. /***  Includes section
  201. ***/
  202. #include "amyboard.h"
  203.  
  204. #include <ctype.h>
  205. #include <utility/tagitem.h>
  206. #include <workbench/startup.h>
  207. #include <workbench/icon.h>
  208. #include <workbench/workbench.h>
  209.  
  210. #include <proto/utility.h>
  211. #include <proto/icon.h>
  212. /**/
  213.  
  214.  
  215. /***  Type definitions
  216. ***/
  217. typedef struct
  218. { STRPTR argName;
  219.   ULONG numNames;
  220.   APTR *valPtr;
  221.   ULONG type;
  222.   ULONG required;
  223.   ULONG multiArgs;
  224.   ULONG numMultiArgs;
  225.   ULONG maxMultiArgs;
  226. } Arg;
  227. /**/
  228.  
  229.  
  230.  
  231. ULONG AddArg(Arg *arg, char *argVal, ULONG argSeen)
  232.  
  233. { ULONG val;
  234.  
  235.   arg->required = FALSE;
  236.  
  237.   if (!arg->valPtr)
  238.   { return(TRUE);
  239.   }
  240.  
  241.   if (!argVal  ||  !argSeen)
  242.   { argVal = "";
  243.   }
  244.  
  245.   switch(arg->type)
  246.   { case PARSEARGS_TYPE_BOOL:
  247.       while(*argVal  &&  isspace(*argVal))
  248.       { ++argVal;
  249.       }
  250.       if (*argVal == '\0')
  251.       { val = !*((ULONG *) arg->valPtr);
  252.       }
  253.       else
  254.       { val = Strnicmp((STRPTR) argVal, (STRPTR) "true", 4) == 0  ||
  255.           Strnicmp((STRPTR) argVal, (STRPTR) "on", 2) == 0    ||
  256.           Strnicmp((STRPTR) argVal, (STRPTR) "yes", 3) == 0;
  257.       }
  258.       break;
  259.     case PARSEARGS_TYPE_INTEGER:
  260.       val = (ULONG) atoi(argVal);
  261.       break;
  262.     case PARSEARGS_TYPE_FLOAT:
  263.       val = (ULONG) atof(argVal);
  264.       break;
  265.     default:
  266.       if (!(val = (ULONG) strdup(argVal)))
  267.       { SetIoErr(ERROR_NO_FREE_STORE);
  268.     return(FALSE);
  269.       }
  270.       break;
  271.   }
  272.  
  273.   if (arg->type == PARSEARGS_TYPE_BOOL  ||
  274.       !arg->multiArgs)
  275.   { *((ULONG *) arg->valPtr) = val;
  276.     return(TRUE);
  277.   }
  278.  
  279.   /**
  280.   ***  Multi argument handling
  281.   **/
  282.   if (arg->maxMultiArgs < arg->numMultiArgs+2)
  283.   { ULONG newmax = MAX(arg->maxMultiArgs*2, 20);
  284.  
  285.     *arg->valPtr = realloc(*arg->valPtr, newmax*sizeof(ULONG));
  286.     if (!(*arg->valPtr))
  287.     { SetIoErr(ERROR_NO_FREE_STORE);
  288.       return(FALSE);
  289.     }
  290.     arg->maxMultiArgs = newmax;
  291.   }
  292.   ((ULONG *) (*arg->valPtr))[arg->numMultiArgs++] = val;
  293.   ((ULONG *) (*arg->valPtr))[arg->numMultiArgs] = (ULONG) NULL;
  294.   return(TRUE);
  295. }
  296.  
  297.  
  298.  
  299.  
  300.  
  301. /***  Input hooks
  302. ***/
  303. _HOOK_FUNC(int, ParseFile, struct Hook *Hook,
  304.                FILE **fp,
  305.                ULONG *error)
  306. { *error = FALSE;
  307.   return(getc(*fp));
  308. }
  309. struct Hook ParseFileHook =
  310. { { NULL, NULL },
  311.   (HOOKFUNC) ParseFile,
  312.   NULL,
  313.   NULL
  314. };
  315.  
  316. _HOOK_FUNC(int, ParseString, struct Hook *hook,
  317.                  char **ptr,
  318.                  ULONG *error)
  319. { int c;
  320.  
  321.   *error = FALSE;
  322.   if ((c = **ptr))
  323.   { (*ptr)++;
  324.   }
  325.   else
  326.   { c = EOF;
  327.   }
  328.   return(c);
  329. }
  330. struct Hook ParseStringHook =
  331. { { NULL, NULL },
  332.   (HOOKFUNC) ParseString,
  333.   NULL,
  334.   NULL
  335. };
  336. /**/
  337.  
  338.  
  339. /*** DisplayArgs function (#ifdef DEBUG_ARGS)
  340. ***/
  341. #ifdef DEBUG_ARGS
  342. void DisplayArgs(Arg *args, ULONG numArgs)
  343.  
  344. { Arg *arg;
  345.   int i;
  346.  
  347.   for (i = 0, arg = args;  i < numArgs;  i++, arg++)
  348.   { char *names = arg->argName;
  349.     int j;
  350.  
  351.     kprintf("Arg %ld: Names = %s", i+1, names);
  352.     for (j = 1;  j < arg->numNames;  j++)
  353.     { names += strlen(names) + 1;
  354.       kprintf(", %s", names);
  355.     }
  356.  
  357.     kprintf("  type = %ld, ", arg->type);
  358.  
  359.     if (arg->valPtr)
  360.     { kprintf("default value = ");
  361.       switch (arg->type)
  362.       { case PARSEARGS_TYPE_BOOL:
  363.       kprintf("%s", *((ULONG *) arg->valPtr) ? "TRUE" : "FALSE");
  364.       break;
  365.     case PARSEARGS_TYPE_INTEGER:
  366.       kprintf("%ld", *((LONG *) arg->valPtr));
  367.       break;
  368.     case PARSEARGS_TYPE_FLOAT:
  369.       kprintf("%f", *((FLOAT *) arg->valPtr));
  370.       break;
  371.     default:
  372.       kprintf("%s", *((STRPTR *) arg->valPtr));
  373.       break;
  374.       }
  375.       kprintf(", argptr = %08lx\n", arg->valPtr);
  376.     }
  377.     else
  378.     { kprintf("Argument not set.\n");
  379.     }
  380.   }
  381. }
  382. #endif
  383. /**/
  384.  
  385.  
  386. /*** DoParseArgs function
  387. ***/
  388. ULONG DoParseArgs(Arg *args, ULONG numArgs, struct Hook *hook, APTR hookData,
  389.           ULONG allowComments, ULONG oneArgPerLine)
  390.  
  391. { char buffer[512]; /*  Argument names and values must not be longer    */
  392.             /*  than this.                                      */
  393.   int c;
  394.   int error = FALSE;
  395.  
  396. #define hget CallHookA(hook, (Object *) &hookData, &error)
  397. #define fillbuffer(p,c)                             \
  398.   { if ((p) != buffer+sizeof(buffer))               \
  399.     { *(p)++ = (c);                                 \
  400.     }                                               \
  401.     else                                            \
  402.     { SetIoErr(ERROR_LINE_TOO_LONG);                \
  403.       return(FALSE);                                \
  404.     }                                               \
  405.   }
  406. #define getarg                                      \
  407.   { if (c == '"')                                   \
  408.     { while ((c = hget) != EOF  &&  c != '"')       \
  409.       { fillbuffer(ptr, c);                         \
  410.       }                                             \
  411.       if (c != EOF)                                 \
  412.       { c = hget;                                   \
  413.       }                                             \
  414.     }                                               \
  415.     else                                            \
  416.     { do                                            \
  417.       { fillbuffer(ptr, c);                         \
  418.     c = hget;                                   \
  419.       }                                             \
  420.       while (c != EOF  &&  !isspace(c));            \
  421.     }                                               \
  422.     *ptr = '\0';                                    \
  423.   }
  424.  
  425.   while ((c  = hget) != EOF)
  426.   { int argSeen = FALSE;
  427.     char *argVal;
  428.     char *ptr = buffer;
  429.     Arg *thisArg;
  430.  
  431.     while (isspace(c))
  432.     { if ((c = hget) == EOF)
  433.       { return(!error);
  434.       }
  435.     }
  436.  
  437.     if (oneArgPerLine)
  438.     { while (c != EOF  &&  c !='\r'  &&   c != '\n')
  439.       { fillbuffer(ptr, c);
  440.     c = hget;
  441.       }
  442.       *ptr = '\0';
  443.  
  444.       if (error)
  445.       { return(FALSE);
  446.       }
  447.  
  448.       if ((argVal = strchr(buffer, '=')))
  449.       { *argVal++ = '\0';
  450.       }
  451.       else if ((argVal = strchr(buffer, ' ')))
  452.       { *argVal++ = '\0';
  453.     while(*argVal  &&  isspace(*argVal))
  454.     { argVal++;
  455.     }
  456.       }
  457.       else
  458.       { argVal = "";
  459.       }
  460.       argSeen = TRUE;
  461.     }
  462.     else
  463.     { getarg;
  464.  
  465.       if ((argVal = strchr(buffer, '=')))
  466.       { argSeen = TRUE;
  467.     *argVal++ = '\0';
  468.       }
  469.       else
  470.       { argSeen = FALSE;
  471.       }
  472.     }
  473.  
  474.     /**
  475.     ***  Find argument
  476.     **/
  477.     { int i;
  478.  
  479.       for (thisArg = args, i = numArgs;
  480.        i;
  481.        --i, ++thisArg)
  482.       { int j;
  483.     STRPTR name;
  484.  
  485.     for (name = thisArg->argName, j = thisArg->numNames;
  486.          j;
  487.          --j, name += strlen((char *) name)+1)
  488.     { if (Stricmp(name, (STRPTR) buffer) == 0  ||
  489.           (*buffer == '-'  &&
  490.            Stricmp(name, (STRPTR) (buffer+1)) == 0))
  491.       { goto Found;
  492.       }
  493.     }
  494.       }
  495.  
  496. Found:
  497.       if (!i)
  498.       { /**
  499.     ***  Argument not found, ignore it
  500.     **/
  501.     continue;
  502.       }
  503.  
  504.       if (thisArg->type != PARSEARGS_TYPE_BOOL  &&  !argSeen)
  505.       { /**
  506.     ***  Check, if another argument follows
  507.     **/
  508.     while (isspace(c))
  509.     { c = hget;
  510.     }
  511.  
  512.     if (c != EOF)
  513.     { argSeen = TRUE;
  514.       argVal = ptr;
  515.       getarg;
  516.     }
  517.     else
  518.     { if (!error)
  519.       { SetIoErr(ERROR_KEY_NEEDS_ARG);
  520.       }
  521.     }
  522.       }
  523.     }
  524.  
  525.     if (error)
  526.     { return(FALSE);
  527.     }
  528.  
  529.     if (!AddArg(thisArg, argVal, argSeen))
  530.     { return(FALSE);
  531.     }
  532.  
  533.   }
  534.   return(!error);
  535. }
  536. /**/
  537.  
  538.  
  539. /*** ParseArgsA function
  540. ***/
  541. ULONG ParseArgsA(int argc, char *argv[], struct TagItem *tags)
  542.  
  543. { ULONG numArgs = 0;
  544.   ULONG namesLen = 0;
  545.   FILE *fp = NULL;
  546.   struct TagItem *ti, *tiptr;
  547.   Arg *args;
  548.   char *helpString = NULL;
  549.   int error = FALSE;
  550.  
  551.   /**
  552.   ***  First scan of tags: Count the arguments
  553.   **/
  554.   tiptr = tags;
  555.   while ((ti = NextTagItem(&tiptr)))
  556.   { switch(ti->ti_Tag)
  557.     { case PARSEARGS_ARGNAME:
  558.     numArgs++;
  559.     namesLen += strlen((char *) ti->ti_Data) + 1;
  560.     break;
  561.     }
  562.   }
  563.  
  564.   if (numArgs == 0) /* Something wrong */
  565.   { return(FALSE);
  566.   }
  567.  
  568.   /**
  569.   ***  Allocate the argument array
  570.   **/
  571.   if (!(args = malloc(sizeof(Arg)*numArgs + namesLen)))
  572.   { return(FALSE);
  573.   }
  574.  
  575.   /**
  576.   ***  Second scan of tags: Initialize the argument array.
  577.   **/
  578.   tiptr = tags;
  579.   { Arg *arg = &args[-1];
  580.     char *namesPtr = (char *) &args[numArgs];
  581.  
  582.     while ((ti = NextTagItem(&tiptr)))
  583.     { switch(ti->ti_Tag)
  584.       { case PARSEARGS_ARGNAME:
  585.       { char *ptr;
  586.         int len;
  587.  
  588.         arg++;
  589.         arg->argName = (STRPTR) (ptr = namesPtr);
  590.         strcpy((char *) arg->argName, (char *) ti->ti_Data);
  591.         len = strlen((char *) arg->argName);
  592.         namesPtr += len+1;
  593.  
  594.         /**
  595.         ***  Count the number of names and separate them with NUL's.
  596.         ***  If the name string was looking like "SN=SHORTNAME",
  597.         ***  we store 'SN\0=SHORTNAME\0'.
  598.         **/
  599.         arg->numNames = 1;
  600.         while ((ptr = strchr(ptr, '=')))
  601.         { arg->numNames++;
  602.           *ptr++ = '\0';
  603.         }
  604.  
  605.         arg->valPtr = NULL;
  606.         arg->type = PARSEARGS_TYPE_STRING;
  607.         arg->multiArgs = FALSE;
  608.         arg->required = FALSE;
  609.         arg->numMultiArgs = 0;
  610.         arg->maxMultiArgs = 0;
  611.         break;
  612.       }
  613.     case PARSEARGS_TYPE:
  614.       arg->type = ti->ti_Data;
  615.       break;
  616.     case PARSEARGS_VALPTR:
  617.       arg->valPtr = (APTR) ti->ti_Data;
  618.       break;
  619.     case PARSEARGS_MULTIARG:
  620.       arg->multiArgs = ti->ti_Data;
  621.       break;
  622.     case PARSEARGS_REQUIRED:
  623.       arg->required = ti->ti_Data;
  624.       break;
  625.     case PARSEARGS_PREFSFILE:
  626.       if (!fp)      /* Open only one prefs file */
  627.       { fp = fopen((char *) ti->ti_Data, "r");
  628.       }
  629.       break;
  630.     case PARSEARGS_HELPSTRING:
  631.       helpString = (char *) ti->ti_Data;
  632.       break;
  633.       }
  634.     }
  635.   }
  636.  
  637. #ifdef DEBUG_ARGS
  638.   kprintf("Default arguments:\n\n");
  639.   DisplayArgs(args, numArgs);
  640. #endif
  641.  
  642.   /**
  643.   ***  Some initializations.
  644.   **/
  645.   { int i;
  646.     Arg *arg;
  647.  
  648.     for (i = numArgs, arg = args;  i > 0;  --i, ++arg)
  649.     { if (arg->type == PARSEARGS_TYPE_BOOL)
  650.       { arg->multiArgs = FALSE;
  651.       }
  652.       else if (arg->multiArgs)
  653.       { if (arg->valPtr)
  654.     { *arg->valPtr = NULL;
  655.     }
  656.       }
  657.     }
  658.   }
  659.  
  660.   /**
  661.   ***  Parse the prefs file, if open.
  662.   **/
  663.   if (fp)
  664.   { while(!feof(fp))
  665.     { if (!DoParseArgs(args, numArgs, &ParseFileHook, fp, TRUE, TRUE))
  666.       { error = TRUE;
  667.     goto ExitParseArgs;
  668.       }
  669.     }
  670.     fclose(fp);
  671.  
  672. #ifdef DEBUG_ARGS
  673.     kprintf("\n\nPrefsfile arguments:\n\n");
  674.     DisplayArgs(args, numArgs);
  675. #endif
  676.   }
  677.  
  678.   /**
  679.   ***  Parse CLI args, if running from CLI.
  680.   **/
  681.   if (argc)
  682.   { char *ptr = (char *) GetArgStr();
  683.  
  684.     while(isspace(*ptr))
  685.     { ++ptr;
  686.     }
  687.  
  688.     if (*ptr == '?'  &&  isspace(*(ptr+1)))     /*  User asked for help  */
  689.     { if (helpString)
  690.       { printf(helpString);
  691.       }
  692.       else
  693.       { int i;
  694.     Arg *arg;
  695.  
  696.     for (i = 0, arg = args;  i < numArgs;  i++, arg++)
  697.     { printf("%s", arg->argName);
  698.       switch(arg->type)
  699.       { case PARSEARGS_TYPE_STRING:
  700.           printf("/K");
  701.           break;
  702.         case PARSEARGS_TYPE_BOOL:
  703.           printf("/T");
  704.           break;
  705.         case PARSEARGS_TYPE_INTEGER:
  706.           printf("/K/N");
  707.           break;
  708.         case PARSEARGS_TYPE_FLOAT:
  709.           printf("/K (float value)");
  710.           break;
  711.       }
  712.     }
  713.       }
  714.  
  715.       if (!DoParseArgs(args, numArgs, &ParseFileHook, stdin, FALSE, FALSE))
  716.       { error = TRUE;
  717.     goto ExitParseArgs;
  718.       }
  719.     }
  720.     else
  721.     { if (!DoParseArgs(args, numArgs, &ParseStringHook, ptr, FALSE, FALSE))
  722.       { error = TRUE;
  723.     goto ExitParseArgs;
  724.       }
  725.     }
  726. #ifdef DEBUG_ARGS
  727.     kprintf("\n\nCLI arguments:\n\n");
  728.     DisplayArgs(args, numArgs);
  729. #endif
  730.   }
  731.   else  /**
  732.     ***  Parse toolkit options, if running from workbench
  733.     **/
  734.   { struct WBStartup *wbenchMsg = (struct WBStartup *) argv;
  735.     struct WBArg *wbarg;
  736.     int i;
  737.  
  738.     for (i = 0, wbarg = wbenchMsg->sm_ArgList;
  739.      i < wbenchMsg->sm_NumArgs;
  740.      i++, wbarg++)
  741.     { BPTR oldDir = (BPTR) NULL; /* Suppress uninitialized warnings */
  742.       ULONG oldDirValid = FALSE;
  743.       struct DiskObject *dobj;
  744.  
  745.       if (wbarg->wa_Lock)
  746.       { oldDir = CurrentDir(wbarg->wa_Lock);
  747.     oldDirValid = TRUE;
  748.       }
  749.  
  750.       if (*wbarg->wa_Name  &&
  751.       (dobj = GetDiskObject((STRPTR) wbarg->wa_Name)))
  752.       { char **toolarray;
  753.  
  754.     for (toolarray = dobj->do_ToolTypes;  *toolarray;  ++toolarray)
  755.     { if (!DoParseArgs(args, numArgs, &ParseStringHook, *toolarray, TRUE, TRUE))
  756.       { error = TRUE;
  757.         break;
  758.       }
  759.     }
  760.     FreeDiskObject(dobj);
  761.       }
  762.  
  763.       if (oldDirValid)
  764.       { CurrentDir(oldDir);
  765.       }
  766.     }
  767.  
  768. #ifdef DEBUG_ARGS
  769.     kprintf("\n\nWorkbench arguments:\n\n");
  770.     DisplayArgs(args, numArgs);
  771. #endif
  772.   }
  773.  
  774.   { int i;
  775.     Arg *arg;
  776.  
  777.     for (i = numArgs, arg = args;  i > 0;  i--, arg++)
  778.     { if (arg->required)
  779.       { SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  780.     break;
  781.       }
  782.     }
  783.   }
  784.  
  785. ExitParseArgs:
  786.  
  787. #ifdef DEBUG_ARGS
  788.   if (error)
  789.   { kprintf("Error %ld while parsing arguments.\n", IoErr());
  790.   }
  791. #endif
  792.   return(!error);
  793. }
  794. /**/
  795.  
  796.  
  797. /*** ParseArgs function
  798. ***/
  799. ULONG ParseArgs(int argc, char *argv[], Tag FirstTag, ...)
  800.  
  801. { return(ParseArgsA(argc, argv, (struct TagItem *) &FirstTag));
  802. }
  803. /**/
  804.